package com.jackrain.nea.dao;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.jackrain.nea.constants.LoginAliveTimeLevel;
import com.jackrain.nea.shiro.stateful.CachingShiroSessionDao;
import com.jackrain.nea.web.face.User;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.shiro.session.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Component;

import java.text.ParseException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author xubin
 * 2017-11-29
 */
@Slf4j
@Component
public class LoginInfoReposity {

    @Autowired
    private CachingShiroSessionDao sessionDao;

//    @Autowired
//    private RedisOpsUtil<String,String> redisOpsUtil;
//
//    private BoundHashOperations getLoginInfoOperation(){
//        return redisOpsUtil.strRedisTemplate.boundHashOps("loginInfo");
//    }
//
//    private String getKey(String sessionId,String userName,String host){
//        return String.format("%s-%s-%s",sessionId,host,userName);
//    }
//
//    public Boolean putLoginInfo(String sessionId, String userName, String host, Date loginTime){
//        String key = getKey(sessionId,userName,host);
//
//        JSONObject value = new JSONObject();
//        value.put("id",sessionId);
//        value.put("username",userName);
//        value.put("host",host);
//        value.put("loginTime",loginTime);
//
//        return getLoginInfoOperation().putIfAbsent(key, JSON.toJSONString(value));
//    }
//
//    public Boolean deleteBySessionId(String sessionId){
//        Map<String,JSONObject> result = query(sessionId,null);
//        for (String key:result.keySet()  ) {
//            getLoginInfoOperation().delete(key);
//        }
//        return true;
//    }
//
//    public Boolean deleteByName(String userName){
//        Map<String,JSONObject> result = query(null,userName);
//        for (String key:result.keySet()  ) {
//            getLoginInfoOperation().delete(key);
//        }
//        return true;
//    }
//
//    public Map<String,JSONObject> query(String sessionId,String userName){
//        StringBuilder pattern = new StringBuilder("*");
//        if(StringUtils.isNotBlank(sessionId)){
//            pattern.append(sessionId).append("*");
//        }
//        if(StringUtils.isNotBlank(userName)){
//            pattern.append(userName).append("*");
//        }
//        Map<String,JSONObject> result = Maps.newHashMap();
//        try (Cursor<Map.Entry<String, String>> datas = (pattern.length()<=1) ?  getLoginInfoOperation().scan(ScanOptions.NONE): getLoginInfoOperation().scan(ScanOptions.scanOptions().match(pattern.toString()).build()))
//        {
//
//        if(datas != null){
//
//            while(datas.hasNext()){
//                Map.Entry<String, String> data = datas.next();
//                String key = new String(data.getKey());
//                String value = new String(data.getValue());
//                JSONObject valueObj = JSONObject.parseObject(value);
//                result.put(key,valueObj);
//            }
//        }
//
//            datas.close();
//        } catch (IOException e) {
//            return result;
//        }
//        return result;
//    }
//
//    public Page<JSONObject> queryList(String sessionId, String userName, Integer pageSize, Integer pageIndex){
//        List<JSONObject> result= Lists.newArrayList();
//        result.addAll(query(sessionId, userName).values());
//
//        Pageable pageRequest = new PageRequest(pageIndex,pageSize);
//        List list = Arrays.asList(Arrays.copyOfRange(result.toArray(),pageIndex*pageSize,(pageIndex+1)*pageSize));
//        Page page = new PageImpl(list,pageRequest,result.size());
//        return page;
//    }

//    private static final SimpleDateFormat inputDate = new SimpleDateFormat("")

    private JSONObject getLoginInfoFromSession(Session session) {
        JSONObject object = new JSONObject();
        User user = (User) session.getAttribute("user");
        object.put("id",session.getId());
        object.put("name", user.getName());
        object.put("ename", user.getEname());
        object.put("loginTime", user.getLastlogindate());
        object.put("host", user.getLastloginip());
        log.info(user.getEname());
        return object;
    }

    private boolean compareDate(String time1, Date time2) throws ParseException {
        //将字符串的时间和传入的时间对比，如果字符串时间为空，则不判断，否则判断到秒
        return DateUtils.truncatedCompareTo(DateUtils.parseDate(time1,"yyyyMMddHHmmss"), time2, Calendar.SECOND) >= 0 ;
    }

    private JSONObject debugLog(JSONObject object){
        log.debug(JSON.toJSONString(object));
        return object;
    }

    private JSONObject genKeeyAlive(JSONObject object){
        if(object==null){
            return object;
        }

        Date loginTime = object.getDate("loginTime");
        if(loginTime != null){
            Date current = new Date();


            Integer days = Integer.valueOf(DateFormatUtils.formatUTC(new Date(current.getTime()-loginTime.getTime()),"dd")) - 1;
            Integer hours = Integer.valueOf(DateFormatUtils.formatUTC(new Date(current.getTime()-loginTime.getTime()),"HH"));
            Integer minutes = Integer.valueOf(DateFormatUtils.formatUTC(new Date(current.getTime()-loginTime.getTime()),"mm"));


            object.put("keepAlive",DateFormatUtils.formatUTC(new Date(current.getTime()-loginTime.getTime()),"HH:mm:ss"));
            Integer totalMinutes = days * 24 *60 + hours * 60 + minutes;
            object.put("totalMinutes",totalMinutes);
            object.put("loginDate", DateFormatUtils.format(loginTime, "yyyy-MM-dd HH:mm:ss"));
        }

        return object;

    }


    public Page<JSONObject> queryList(String sessionId, String userName, Integer pageSize, Integer pageIndex, String startTime, String endTime, LoginAliveTimeLevel aliveTimeLevel) {

        List<JSONObject> result =     sessionDao.getActiveSessions().stream().parallel()
            .filter((session) -> session.getAttribute("user") != null)
            .map((session) -> getLoginInfoFromSession(session))
            .filter((jsonObject) ->
                (StringUtils.isBlank(userName)?true:
                        (jsonObject.getString("name").contains(userName)
                                ||jsonObject.getString("ename").contains(userName)
                                ||jsonObject.getString("host").contains(userName)))
            )
            .filter((jsonObject) -> {
                try {
                    return ((StringUtils.isBlank(startTime) || jsonObject.getDate("loginTime") == null) ? true : !compareDate(startTime, jsonObject.getDate("loginTime")));
                } catch (ParseException e) {
                    log.error(e.getMessage(),e);
                    return true;
                }
            })
            .filter((jsonObject) -> {
                try {
                    return (StringUtils.isBlank(endTime) || jsonObject.getDate("loginTime") == null ? true : compareDate(endTime, jsonObject.getDate("loginTime")));
                } catch (ParseException e) {
                    log.error(e.getMessage(),e);
                    return true;
                }
            })
            .map((jsonObject)-> genKeeyAlive(jsonObject))
            .filter((jsonObject -> {
                if(aliveTimeLevel == null){
                    return true;
                }
                if(!jsonObject.containsKey("totalMinutes")){
                    return true;
                }
                Integer totalMinutes = jsonObject.getInteger("totalMinutes");
                switch (aliveTimeLevel){
                    case MORE_THAN_THREE:
                        if( aliveTimeLevel.getMinMinutes() <= totalMinutes){
                            return true;
                        }else{
                            return false;
                        }
                    default:
                        if( aliveTimeLevel.getMinMinutes() <= totalMinutes && aliveTimeLevel.getMaxMinutes() >= totalMinutes){
                            return true;
                        }else{
                            return false;
                        }
                }
            }))

            .collect(Collectors.toList());


        Pageable pageRequest = new PageRequest(pageIndex, pageSize);

        int from = pageIndex * pageSize;
        int to = from + pageSize;
        if(to > result.size()){
            to = result.size();
        }

        List list =from >= result.size()?Lists.newArrayList(): Arrays.asList(Arrays.copyOfRange(result.toArray(new JSONObject[ to - from ]), from, to));
        Page page = new PageImpl(list, pageRequest, result.size());
        return page;
    }
}
